/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#[cfg(feature = "simd")]
use rocketmq_error::SerializationError;

/// SIMD-accelerated JSON utility for high-performance serialization and deserialization.
///
/// This utility leverages SIMD instructions for faster JSON processing compared to standard
/// serde_json. It's particularly beneficial for:
/// - High-throughput message processing
/// - Large JSON payloads
/// - Performance-critical paths
///
/// # Performance Characteristics
///
/// Based on benchmarks:
/// - Encoding: ~5% faster than serde_json
/// - Decoding: ~10% faster than serde_json
/// - Roundtrip: ~23% faster than serde_json
/// - Throughput: ~30% higher than serde_json
///
/// # Feature Flag
///
/// This module requires the `simd` feature flag to be enabled.
///
/// # Example
///
/// ```ignore
/// use rocketmq_common::utils::simd_json_utils::SimdJsonUtils;
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Serialize, Deserialize)]
/// struct Message {
///     topic: String,
///     body: Vec<u8>,
/// }
///
/// let msg = Message {
///     topic: "test".to_string(),
///     body: vec![1, 2, 3],
/// };
///
/// // Serialize
/// let json_string = SimdJsonUtils::serialize_json(&msg)?;
/// let json_bytes = SimdJsonUtils::serialize_json_vec(&msg)?;
///
/// // Deserialize
/// let msg_from_str: Message = SimdJsonUtils::from_json_str(&json_string)?;
/// let msg_from_bytes: Message = SimdJsonUtils::from_json_slice(&json_bytes)?;
/// ```
#[cfg(feature = "simd")]
pub struct SimdJsonUtils;

#[cfg(feature = "simd")]
impl SimdJsonUtils {
    /// Deserialize JSON from bytes into a Rust type using SIMD acceleration.
    ///
    /// This method requires a mutable byte slice as simd-json modifies the input
    /// buffer in-place for performance. If you need to preserve the original data,
    /// clone it first.
    ///
    /// # Arguments
    ///
    /// * `bytes` - A mutable byte slice containing JSON data
    ///
    /// # Returns
    ///
    /// Returns the deserialized value or an error if parsing fails.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let mut json_data = br#"{"key":"value"}"#.to_vec();
    /// let result: HashMap<String, String> = SimdJsonUtils::from_json_bytes(&mut json_data)?;
    /// ```
    #[inline]
    pub fn from_json_bytes<T>(bytes: &mut [u8]) -> rocketmq_error::RocketMQResult<T>
    where
        T: serde::de::DeserializeOwned,
    {
        simd_json::from_slice(bytes)
            .map_err(|e| SerializationError::decode_failed("SIMD-JSON", e.to_string()).into())
    }

    /// Deserialize JSON from a mutable byte slice into a Rust type.
    ///
    /// This is an alias for `from_json_bytes` for consistency with the SerdeJsonUtils API.
    #[inline]
    pub fn from_json_slice<T>(bytes: &mut [u8]) -> rocketmq_error::RocketMQResult<T>
    where
        T: serde::de::DeserializeOwned,
    {
        Self::from_json_bytes(bytes)
    }

    /// Deserialize JSON from a string into a Rust type using SIMD acceleration.
    ///
    /// This method creates a mutable copy of the input string for simd-json processing.
    ///
    /// # Arguments
    ///
    /// * `json` - A string slice containing JSON data
    ///
    /// # Returns
    ///
    /// Returns the deserialized value or an error if parsing fails.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let json_str = r#"{"key":"value"}"#;
    /// let result: HashMap<String, String> = SimdJsonUtils::from_json_str(json_str)?;
    /// ```
    #[inline]
    pub fn from_json_str<T>(json: &str) -> rocketmq_error::RocketMQResult<T>
    where
        T: serde::de::DeserializeOwned,
    {
        let mut bytes = json.as_bytes().to_vec();
        simd_json::from_slice(&mut bytes)
            .map_err(|e| SerializationError::decode_failed("SIMD-JSON", e.to_string()).into())
    }

    /// Serialize a Rust type into a JSON string (compact format) using SIMD acceleration.
    ///
    /// # Arguments
    ///
    /// * `value` - A reference to the value to serialize
    ///
    /// # Returns
    ///
    /// Returns a JSON string or an error if serialization fails.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let data = vec!["hello", "world"];
    /// let json_string = SimdJsonUtils::serialize_json(&data)?;
    /// ```
    #[inline]
    pub fn serialize_json<T>(value: &T) -> rocketmq_error::RocketMQResult<String>
    where
        T: serde::Serialize,
    {
        simd_json::to_string(value)
            .map_err(|e| SerializationError::encode_failed("SIMD-JSON", e.to_string()).into())
    }

    /// Serialize a Rust type into a JSON string (pretty-printed format).
    ///
    /// Note: simd-json doesn't have native pretty-print support, so this falls back
    /// to serde_json for pretty printing.
    ///
    /// # Arguments
    ///
    /// * `value` - A reference to the value to serialize
    ///
    /// # Returns
    ///
    /// Returns a pretty-printed JSON string or an error if serialization fails.
    #[inline]
    pub fn serialize_json_pretty<T>(value: &T) -> rocketmq_error::RocketMQResult<String>
    where
        T: serde::Serialize,
    {
        // simd-json doesn't support pretty printing, fall back to serde_json
        Ok(serde_json::to_string_pretty(value)?)
    }

    /// Serialize a Rust type into a JSON byte vector (compact format) using SIMD acceleration.
    ///
    /// # Arguments
    ///
    /// * `value` - A reference to the value to serialize
    ///
    /// # Returns
    ///
    /// Returns a JSON byte vector or an error if serialization fails.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let data = vec!["hello", "world"];
    /// let json_bytes = SimdJsonUtils::serialize_json_vec(&data)?;
    /// ```
    #[inline]
    pub fn serialize_json_vec<T>(value: &T) -> rocketmq_error::RocketMQResult<Vec<u8>>
    where
        T: serde::Serialize,
    {
        simd_json::to_vec(value)
            .map_err(|e| SerializationError::encode_failed("SIMD-JSON", e.to_string()).into())
    }

    /// Serialize a Rust type into a JSON byte vector (pretty-printed format).
    ///
    /// Note: simd-json doesn't have native pretty-print support, so this falls back
    /// to serde_json for pretty printing.
    ///
    /// # Arguments
    ///
    /// * `value` - A reference to the value to serialize
    ///
    /// # Returns
    ///
    /// Returns a pretty-printed JSON byte vector or an error if serialization fails.
    #[inline]
    pub fn serialize_json_vec_pretty<T>(value: &T) -> rocketmq_error::RocketMQResult<Vec<u8>>
    where
        T: serde::Serialize,
    {
        // simd-json doesn't support pretty printing, fall back to serde_json
        Ok(serde_json::to_vec_pretty(value)?)
    }

    /// Serialize a Rust type into a JSON byte vector using a preallocated writer.
    ///
    /// This is more efficient when you already have a buffer to write into.
    ///
    /// # Arguments
    ///
    /// * `writer` - A mutable reference to a Vec<u8> to write JSON into
    /// * `value` - A reference to the value to serialize
    ///
    /// # Returns
    ///
    /// Returns Ok(()) on success or an error if serialization fails.
    #[inline]
    pub fn serialize_json_to_writer<T>(
        writer: &mut Vec<u8>,
        value: &T,
    ) -> rocketmq_error::RocketMQResult<()>
    where
        T: serde::Serialize,
    {
        simd_json::to_writer(writer, value)
            .map_err(|e| SerializationError::encode_failed("SIMD-JSON", e.to_string()).into())
    }
}

#[cfg(all(test, feature = "simd"))]
mod tests {
    use serde::Deserialize;
    use serde::Serialize;
    use serde_json::json;
    use serde_json::Value;

    use super::*;

    #[derive(Serialize, Deserialize, Debug, PartialEq)]
    struct TestStruct {
        name: String,
        age: u8,
    }

    #[test]
    fn test_from_json_str_success() {
        let json_str = r#"{"name":"Alice","age":30}"#;
        let expected = TestStruct {
            name: "Alice".to_string(),
            age: 30,
        };
        let result: TestStruct = SimdJsonUtils::from_json_str(json_str).unwrap();
        assert_eq!(result, expected);
    }

    #[test]
    fn test_from_json_str_error() {
        let json_str = r#"{"name":"Alice","age":"thirty"}"#;
        let result: rocketmq_error::RocketMQResult<TestStruct> =
            SimdJsonUtils::from_json_str(json_str);
        assert!(result.is_err());
    }

    #[test]
    fn test_from_json_bytes_success() {
        let mut json_data = br#"{"name":"Bob","age":25}"#.to_vec();
        let expected = TestStruct {
            name: "Bob".to_string(),
            age: 25,
        };
        let result: TestStruct = SimdJsonUtils::from_json_bytes(&mut json_data).unwrap();
        assert_eq!(result, expected);
    }

    #[test]
    fn test_from_json_bytes_error() {
        let mut json_data = br#"{"name":"Bob","age":"twenty-five"}"#.to_vec();
        let result: rocketmq_error::RocketMQResult<TestStruct> =
            SimdJsonUtils::from_json_bytes(&mut json_data);
        assert!(result.is_err());
    }

    #[test]
    fn test_from_json_slice_success() {
        let mut json_slice = br#"{"name":"Charlie","age":35}"#.to_vec();
        let expected = TestStruct {
            name: "Charlie".to_string(),
            age: 35,
        };
        let result: TestStruct = SimdJsonUtils::from_json_slice(&mut json_slice).unwrap();
        assert_eq!(result, expected);
    }

    #[test]
    fn test_serialize_json_success() {
        let value = TestStruct {
            name: "David".to_string(),
            age: 40,
        };
        let result: String = SimdJsonUtils::serialize_json(&value).unwrap();
        // simd-json may produce slightly different formatting
        assert!(result.contains("David"));
        assert!(result.contains("40"));
    }

    #[test]
    fn test_serialize_json_vec_success() {
        let value = TestStruct {
            name: "Eve".to_string(),
            age: 28,
        };
        let result: Vec<u8> = SimdJsonUtils::serialize_json_vec(&value).unwrap();
        let result_str = String::from_utf8(result).unwrap();
        assert!(result_str.contains("Eve"));
        assert!(result_str.contains("28"));
    }

    #[test]
    fn test_serialize_json_pretty_success() {
        let value = TestStruct {
            name: "Frank".to_string(),
            age: 45,
        };
        let result: String = SimdJsonUtils::serialize_json_pretty(&value).unwrap();
        // Pretty print should have newlines
        assert!(result.contains('\n'));
        assert!(result.contains("Frank"));
    }

    #[test]
    fn test_serialize_json_vec_pretty_success() {
        let value = TestStruct {
            name: "Grace".to_string(),
            age: 32,
        };
        let result: Vec<u8> = SimdJsonUtils::serialize_json_vec_pretty(&value).unwrap();
        let result_str = String::from_utf8(result).unwrap();
        assert!(result_str.contains('\n'));
        assert!(result_str.contains("Grace"));
    }

    #[test]
    fn test_serialize_json_to_writer_success() {
        let value = TestStruct {
            name: "Henry".to_string(),
            age: 50,
        };
        let mut writer = Vec::new();
        let result = SimdJsonUtils::serialize_json_to_writer(&mut writer, &value);
        assert!(result.is_ok());
        let result_str = String::from_utf8(writer).unwrap();
        assert!(result_str.contains("Henry"));
        assert!(result_str.contains("50"));
    }

    #[test]
    fn test_roundtrip() {
        let original = TestStruct {
            name: "Isabella".to_string(),
            age: 27,
        };

        // Serialize
        let json_str = SimdJsonUtils::serialize_json(&original).unwrap();

        // Deserialize
        let deserialized: TestStruct = SimdJsonUtils::from_json_str(&json_str).unwrap();

        assert_eq!(original, deserialized);
    }

    #[test]
    fn test_complex_types() {
        let value = json!({
            "string": "test",
            "number": 42,
            "boolean": true,
            "null": null,
            "array": [1, 2, 3],
            "object": {"nested": "value"}
        });

        let json_str = SimdJsonUtils::serialize_json(&value).unwrap();
        let deserialized: Value = SimdJsonUtils::from_json_str(&json_str).unwrap();

        assert_eq!(value["string"], deserialized["string"]);
        assert_eq!(value["number"], deserialized["number"]);
        assert_eq!(value["boolean"], deserialized["boolean"]);
    }

    #[test]
    fn test_large_payload() {
        let large_struct = TestStruct {
            name: "X".repeat(1000),
            age: 99,
        };

        let json_vec = SimdJsonUtils::serialize_json_vec(&large_struct).unwrap();
        let mut json_vec_mut = json_vec.clone();
        let deserialized: TestStruct = SimdJsonUtils::from_json_bytes(&mut json_vec_mut).unwrap();

        assert_eq!(large_struct, deserialized);
    }

    #[test]
    fn test_empty_struct() {
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct EmptyStruct {}

        let empty = EmptyStruct {};
        let json_str = SimdJsonUtils::serialize_json(&empty).unwrap();
        let deserialized: EmptyStruct = SimdJsonUtils::from_json_str(&json_str).unwrap();

        assert_eq!(empty, deserialized);
    }

    #[test]
    fn test_vector_serialization() {
        let vec_data = vec![1, 2, 3, 4, 5];
        let json_str = SimdJsonUtils::serialize_json(&vec_data).unwrap();
        let deserialized: Vec<i32> = SimdJsonUtils::from_json_str(&json_str).unwrap();

        assert_eq!(vec_data, deserialized);
    }
}
